/*
  Systems Programming Assignment
  Submitted by
	       Thomas Jacob
	       Roll no. 5036
	       R-5, TKMCE.

  A simple SIC Assembler - implemented as two passes
		Pass1                 Pass2
  Source program --> Intermediate file --> Object program

  Assembler supports the following directives : -
	  START, END, BYTE, WORD, RESB, RESW.
  The source program to be assembled is to be organized as:
      BYTES  1-8  Label
	       9  Blank
	    10-15 Operation code
	    16-17 Blank
	    18-35 Operand
	    36-66 Comment
*/

/*SICTOM.CPP*/

#include"headers.h"
#include "optab.cpp"
#include "symtab.cpp"
#include "fileops.cpp"
#include "sline.cpp"
#include "miscops.cpp"

char s[81];
char *fname,*buffer,reclen[3],*progname,*t;
int ERRFLAG=0,bufflen;
int startaddr,proglength,txtstart,addr;
symtabtype SYMTAB;
optabtype OPTAB;
FILE *obj;


void pass1();
void pass2();
void buffwrite(char *cd);
void buffinit();
char *byteval();
char *wordval();
char *blank(int);
int streql(char *x,char *y);

void main()
{

 //Prompt for source file
 fname=new char[80];
 cout<<"\nFilename: ";
 cin>>fname;
 src=fopen(fname,"r");
 if(src) pass1();  else { cout<<"File open error.";exit(1);}
 fclose(src);
 if(!ERRFLAG) pass2();
}

char *blank(int n)
{
 char *str;
 str=new char[n+1];
 for(int i=0;i<n;i++)
  str[i]=' ';
 str[i]='\0';
 return(str);
}

char *left8(char *t)
{
 char *str;
 *(t+8)='\0';
 return(t);
}

int streql(char *x,char *y)
{
 if(!strcmp(x,y)) return(1);
 else return(0);
}

void buffwrite(char *cd)
{
 strcat(buffer,cd);
 bufflen+=strlen(cd);
}

//To make address 6 bytes long
char *makeaddr(char *s)
{
 char *temp;
 int i;
 temp=new char[8];

 if(strlen(s)==6) strcpy(temp,s);
 else
 {
  for(i=0;i<6-strlen(s);i++)
   *(temp+i)='0';
  *(temp+i)='\0';

  strncat(temp,s,strlen(s));
 }
 return(temp);
}

void buffinit()
{
 fprintf(obj,"%s\n",strupr(buffer));
 buffer=new char[69];
 strcpy(buffer,"T");
 strcat(buffer,makeaddr(itoa(line.address,t,16)));
 strcat(buffer,blank(2));
 bufflen=9;
 txtstart=line.address;
}

char *byteval(char *x)
{
 char str[5],newstr[3];
 strncpy(str,x,4);
 *newstr=str[2];
 *(newstr+1)=str[3];
 *(newstr+2)='\0';
 int n=atoi(newstr);
 return(itoa(n,t,16));
}

char *wordval(char *x)
{
 char str[5];
 strncpy(str,x,4);
 return(makeaddr(itoa(atoi(str),t,16)));
}
//Create intermediate file
void pass1()
{
   FILE *inter;
   inter=fopen("temp.int","w");
   locctr=0;
   int incr=0;
   ERRFLAG=0;

   if(!feof(src))
   do
    {
     strcpy(s,readline(src));
     srcline sli(s);
     if (streql(line.opcode,"START "))
      {
       locctr=hex2num(line.operand);
       startaddr=locctr;
       fwrite(&line,sizeof(line),1,inter);
       progname=new char[7];
       strncpy(progname,line.label,6);
       *(progname+6)='\0';
      }
     else if (!sli.iscomm())
      {
       if (!streql(line.label,blank(8)))
	{
	 if(SYMTAB.access(0,line.label))
	  {
	   ERRFLAG=1;
	   cout<<"Duplicate symbol."<<line.label;
	   exit(1);
	  }
	 SYMTAB.access(1,line.label);
	}

       if (OPTAB.ismnemonic(line.opcode)) incr=3;
       else if (streql(line.opcode,"WORD  ")) incr=3;
       else if (streql(line.opcode,"RESW  ")) incr=3*atoi(line.operand);
       else if (streql(line.opcode,"RESB  ")) incr=atoi(line.operand);
       else if (streql(line.opcode,"BYTE  ")) incr=3;
       else if (streql(line.opcode,"END   "))
	 {
	 line.address=locctr+incr;
	 fwrite(&line,sizeof(line),1,inter);
	 break;
	 }
       else ERRFLAG=1;

       line.address=locctr;
       locctr+=incr;
       fwrite(&line,sizeof(line),1,inter);
    }//end of iscomm
   }while(!feof(src));

  proglength=locctr-startaddr;
  fclose(inter);
  if(ERRFLAG) { cout<<"\nFatal error.\n"; exit(1);}
}

void pass2()
{
 char *code;
 obj=fopen("out.obj","w");
 src=fopen("temp.int","r");

 fread(&line,sizeof(line),1,src);//header
 buffer=new char[20];
 strcpy(buffer,"H");
 strcat(buffer,progname);
 strcat(buffer,makeaddr(itoa(startaddr,t,16)));
 strcat(buffer,itoa(proglength,t,16));

 //text and end records
 fread(&line,sizeof(line),1,src);
 buffinit();
 while (!feof(src))
 {
   code=new char[7];
   if (!streql(line.opcode,"END   "))
    {
     if(OPTAB.ismnemonic(line.opcode))
      {
	strcpy(code,OPTAB.codeof(line.opcode));
	if(!streql(line.operand,blank(18)))
	 {
	  if(SYMTAB.access(0,left8(line.operand)))
	    {
	     strcat(code,makeaddr(itoa(SYMTAB.locof(left8(line.operand)),t,16)));
	    }
	  else  //operand-not-in-symtab
	    {
	     strcat(code,"0000");
	     ERRFLAG=1;
	     cout<<"Invalid operand:  "<<line.operand<<"\n";
	     break;
	    }
	 }
	else  //no-operand
	strcat(code,"0000");
      }
     else //opcode-not-in-optab
      {
       if (streql(line.opcode,"BYTE  ")) strcpy(code,byteval(line.operand));
       else if (streql(line.opcode,"WORD  ")) strcpy(code,wordval(line.operand));
       else if (streql(line.opcode,"RESB  ")) strcpy(code,"");
       else if (streql(line.opcode,"RESW  ")) strcpy(code,"");
      }
     if(bufflen+6<=69) buffwrite(code);
     else
     {
      strcpy(reclen,itoa((line.address-txtstart),t,16));
      *(buffer+7)=reclen[0];*(buffer+8)=reclen[1];
      buffinit();
      buffwrite(code);
     }
    } //opcode=end
   else
   {
   fprintf(obj,"E%s",strupr(makeaddr(itoa(startaddr,t,16))));
   break;
   }
  fread(&line,sizeof(line),1,src);
  }//end-of-while
 fclose(obj);
 fclose(src);
}
